/**
* Copyright (C) 2015 BITPlan GmbH
*
* Pater-Delp-Str. 1
* D-47877 Willich-Schiefbahn
*
* http://www.bitplan.com
*
* This source is part of
* https://github.com/WolfgangFahl/Mediawiki-Japi
* and the license for Mediawiki-Japi applies
*
*/
package com.bitplan.mediawiki.japi.user;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* Encryption class to be use for password encryption for test cases
* @author wf
*
*/
public class Crypt {
private char[] cypher;
byte[] salt;
/**
* @return the cypher
*/
public String getCypher() {
return new String(cypher);
}
/**
* return the salt
* @return the salt
*/
public String getSalt() {
return new String(salt);
}
/**
* @param cypher the cypher to set
*/
public void setCypher(char[] cypher) {
this.cypher = cypher;
}
/**
* create me from a password and salt
*
* @param pCypher
* @param pSalt
*/
Crypt(String pCypher, String pSalt) {
this.setCypher(pCypher.toCharArray());
this.salt = pSalt.getBytes();
}
/**
* generate a Random key
* @param pLength
* @return the reandom key with the given length
*/
public static String generateRandomKey(int pLength) {
int asciiFirst = 48;
int asciiLast = 122;
Integer[] exceptions = { 58,59,60,61,62,63,91,92,93,94,96 };
List<Integer> exceptionsList = Arrays.asList(exceptions);
SecureRandom random = new SecureRandom();
StringBuilder builder = new StringBuilder();
for (int i=0; i<pLength; i++) {
int charIndex;
do {
charIndex = random.nextInt(asciiLast - asciiFirst + 1) + asciiFirst;
}
while (exceptionsList.contains(charIndex));
builder.append((char) charIndex);
}
return builder.toString();
}
/**
* get a random Crypt
* @return a new crypt with a 32 byte random key and 8byte salt
*/
public static Crypt getRandomCrypt() {
String lCypher=generateRandomKey(32);
String lSalt=generateRandomKey(8);
Crypt result=new Crypt(lCypher,lSalt);
return result;
}
/**
* test this
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Crypt pcf=getRandomCrypt();
String originalPassword = "secretPassword";
System.out.println("Original password: " + originalPassword);
String encryptedPassword = pcf.encrypt(originalPassword);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = pcf.decrypt(encryptedPassword);
System.out.println("Decrypted password: " + decryptedPassword);
}
/**
* encrypt the given property
* @param property
* @return
* @throws GeneralSecurityException
* @throws UnsupportedEncodingException
*/
String encrypt(String property) throws GeneralSecurityException,
UnsupportedEncodingException {
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(cypher));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(salt, 20));
return base64Encode(pbeCipher.doFinal(property.getBytes("UTF-8")));
}
private static String base64Encode(byte[] bytes) {
return new BASE64Encoder().encode(bytes);
}
String decrypt(String property) throws GeneralSecurityException,
IOException {
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(cypher));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(salt, 20));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}
private static byte[] base64Decode(String property) throws IOException {
return new BASE64Decoder().decodeBuffer(property);
}
}